/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief Example types for a Unit interface. ___Remember to rewrite this too!!___
 * \author Antti Maula <antti.maula@tkk.fi>
 *
 * $Id: UnitTypes.hpp,v 1.7 2009-05-13 07:18:16 amaula Exp $
 *
 */
#ifndef _MACI_UNITTYPES_HPP_
#define _MACI_UNITTYPES_HPP_
#include <inttypes.h>
#include "ownutils.h"
#include "owndebug.h"
#include <string>
#include <vector>

namespace MaCI {

  /** MaCI - Unit interface.
   *
   * This namespace contains all the methods and types related
   * to the Unit interface.
   *
   * \note This interface is still under heavy developement. Please
   * consider this interface to be on Alpha stage of testing before
   * this note is removed!
   */
  namespace Unit {
    
    /** Enumeration types for Unit data elements.
     */
    enum EElementType { 
      KTypeUnknown               = -1, ///< Unkown type.
      KTypeTimestamp             = 1,  ///< Common::TTimestamp element.
      KTypeCommand               = 2,  ///< TCommand element.
      KTypeUnitId                = 3,  ///< Unit identifier.
      KTypeAvailableUnit         = 4,  ///< TAvailableUnit element.
      KTypeActiveUnit            = 5,  ///< TActiveUnit element.
      KTypeUnitPose              = 6,  ///< TUnitInfo element.
      KTypeParametersText        = 7   ///< Text formatted parameters (Implementation specific!)
    };


    /** Enumerations for Unit Command.
     */
    enum EUnitCommand { 
      /**  Get available units.
       *
       * This command is sent without parameters.  Reply to this
       * command includes: n-count of TAvailableUnit entities. Each
       * TAvailableUnit entity is accompanied by two sequentical Text
       * containers for "implementation" and "description" (in this
       * order)
       */
      KCommandGetAvailableUnits = 1,

      /** Get active units.
       *
       */
      KCommandGetActiveUnits    = 2,

      /// Create Unit
      KCommandCreateUnit        = 3,

      /// Delete Unit
      KCommandDeleteUnit        = 4
    };


    /** Enumeration for different Unit types.
     *
     */
    enum EUnitType {
      KUnitTypeUnknown           = 0,
      KUnitTypeMachine           = 1,
      KUnitTypeHexahedron        = 2,
      KUnitTypeSphere            = 3,
      KUnitTypeCylinder          = 4
    };


    /** Flags for the command
     */
    enum ECommandFlags {
      KCommandFlagNone           = 0,
      KCommandFlagReply          = 1,
      KCommandFlagResultOK       = 2,
      KCommandFlagResultError    = 3
    };


    /** Unit command.
     *
     * This structure contains command field to be used when sending
     * action requests to Unit enabled clients.
     *
     * \see EUnitCommand
     */
    struct TCommand 
    {
      TCommand(const unsigned int &aCmd = 0,
               const unsigned int &aFlags = 0)
        : cmd(aCmd),
          flags(aFlags) {}
      uint16_t cmd;             ///< Command
      uint16_t flags;           ///< Flags for the commands
    };
    

    struct TAvailableUnit
    {
      TAvailableUnit(const uint32_t &aAvailableId = 0,
                     const uint32_t &aUnit_type = 0,
                     const std::string &aImplementation = "")
        : available_id(aAvailableId),
          unit_type(aUnit_type),
          implementation() {
        strncpy(implementation, aImplementation.c_str(), sizeof(implementation));
        implementation[sizeof(implementation)-1] = '\0';
      }
      bool operator==(const TAvailableUnit &aRef) const {
        return (aRef.available_id == this->available_id) ||
          (aRef.unit_type == this->unit_type && 
           strncmp(implementation, aRef.implementation, sizeof(implementation)) == 0);
      }
      uint32_t available_id;   ///< Available unit ID.
      uint32_t unit_type;      ///< Unit type. (large enough ;)
      char implementation[32]; ///< Implementation name.
    };

    /// Type defining multiple of TAvailableUnit
    typedef std::vector<TAvailableUnit> TAvailableUnitArray;
    

    struct TUnitId
    {
      TUnitId(const uint32_t &aAvailableId = 0,
              const uint32_t &aActiveId = 0,
              const std::string &aInstance = "") 
        : available_id(aAvailableId),
          active_id(aActiveId),
          instance() {
        strncpy(instance, aInstance.c_str(), sizeof(instance));
        instance[sizeof(instance)-1] = '\0';
      }
      bool operator==(const TUnitId &aRef) const {
        bool r;
        r = aRef.active_id == this->active_id;
        r |= (aRef.available_id == this->available_id && 
              strncmp(instance, aRef.instance, sizeof(instance)) == 0);
        return r;
      }
      uint32_t available_id;  ///< Available Unit ID (If applicable)
      uint32_t active_id;     ///< Active ID (If applicable)
      char instance[32];      ///< Instance name
    };

    typedef TUnitId TActiveUnit;
    
    /// Type defining multiple of TActiveUnit
    typedef std::vector<TActiveUnit> TActiveUnitArray;

    

    

    /** Unit Pose structure.
     *
     * This structure contains information about current Pose status
     * of a unit entity.
     *
     */
    struct TUnitPose
    {
      TUnitPose(const float &aX = 0.00, const float &aY = 0.00, const float &aZ = 0.00,
                const float &aX_rot = 0.00, const float &aY_rot = 0.00, const float &aZ_rot = 0.00 )
        : x_pos(aX),
          y_pos(aY),
          z_pos(aZ),
          x_angle(aX_rot),
          y_angle(aY_rot),
          z_angle(aZ_rot) {}
      float x_pos;                  ///< X position
      float y_pos;                  ///< Y position
      float z_pos;                  ///< Z position
      float x_angle;                ///< X rotation
      float y_angle;                ///< Y rotation
      float z_angle;                ///< Z rotation (heading)
    };


    /** Unit event predefined types.
     */
    enum EUnitEventType { 
      /** Unknown event type.
       *
       * This event type should never be sent
       * over to remote end.
       */
      KEventTypeUnknown          = 0,


      /** Unit Info event
       *
       */
      KEventTypeUnitInfo         = 1
    };


    /** Unit event.
     *
     * This structure contains event data for a Unit event.
     */
    struct TUnitEvent {
      TUnitEvent(const unsigned int aEventType = KEventTypeUnknown)
        : type(aEventType) {}      
      uint32_t type;     ///< Event type. See type EUnitEventType.
    };
  }
}

#endif
